package cn.itcast.cralwe_jd.utils;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;

/**
 *  定义Http工具类：封装HttpClient，简化爬虫开发
 *  1. 使用HttpClient池化技术实现客户端浏览器对象的创建和回收，简化开发，提高效率，避免额外资源的开销
 *  2. 该工具类实现的API：html页面的获取，图片的获取
 */
@SuppressWarnings("all")
@Component // 将该工具类交给Spring管理
public class HttpUtils {
    // 定义HttpClient连接池对象
    private PoolingHttpClientConnectionManager connectionManager;

    public HttpUtils() {
        // 创建连接池对象
        this.connectionManager = new PoolingHttpClientConnectionManager();
        // 设置相关的连接参数
        this.connectionManager.setMaxTotal(100); // 最大连接池数量
        this.connectionManager.setDefaultMaxPerRoute(10); // 当前主机的连接池数量
    }


    /**
     * 根据url地址获取html页面
     * @param url
     * @return
     */
    public String doGetHtml(String url) {
        // 从连接池冲获取HttpClient对象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.connectionManager).build();

        // 创建HttpGet对象  实现Get请求
        HttpGet httpGet = new HttpGet(url); // 设置请求路径

        // 设置http相关参数
        httpGet.setConfig(this.getConfig());

        // 创建响应对象
        CloseableHttpResponse response = null;

        try {
            // 获取响应对象
            response = httpClient.execute(httpGet);

            // 判断当前响应是否成功
            if (response.getStatusLine().getStatusCode() == 200) {
                // 如果当前的状态码为200，表明响应成功，获取内容
                String content = EntityUtils.toString(response.getEntity(), "utf8");

                return content; // 返回
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (response != null) { // 防止空指针异常，先做空判断
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // 由于使用池化技术，所以我们不需要手动释放HttpClient对象的资源，完全交由连接池来管理
        }
        return ""; // 如果没有成功直接放回空字符串
    }

    /**
     * 根据图片的url地址获取图片
     * @param url
     * @return
     */
    public String doGetImage(String url) {
        // 从连接池冲获取HttpClient对象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(this.connectionManager).build();

        // 创建HttpGet对象  实现Get请求
        HttpGet httpGet = new HttpGet();

        // 设置http相关参数
        httpGet.setConfig(this.getConfig());

        // 创建响应对象
        CloseableHttpResponse response = null;

        try {
            // 获取响应对象
            response = httpClient.execute(httpGet);

            // 判断当前响应是否成功
            if (response.getStatusLine().getStatusCode() == 200) {
                // 判断响应以是否为空
                if (response.getEntity() != null) {
                    // 如果不为空，下载图片到本地磁盘中
                    // 获取图片
                    // 获取图片的后缀
                    String extName = url.substring(url.lastIndexOf("."));

                    // 创建图片名称 使用UUID工具类  文件名+后缀名(完整的图片名称)
                    String imageName = UUID.randomUUID().toString() + extName;

                    // 下载图片(下载到本地磁盘中)
                    // 创建文件File
                    String path = "C:\\Users\\tomcat\\Desktop\\jd_images\\"; // 设置存放的磁盘地址
                    path += imageName; // 完整路径
                    File file = new File(path);
                    // 创建流式对象用于下载图片到磁盘,需要将File对象传递给当前流式对象
                    OutputStream outputStream = new FileOutputStream(file);
                    response.getEntity().writeTo(outputStream); // 实现下载

                    // 返回图片名称
                    return imageName;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (response != null) { // 防止空指针异常，先做空判断
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // 由于使用池化技术，所以我们不需要手动释放HttpClient对象的资源，完全交由连接池来管理
        }
        return ""; // 如果没有成功直接放回空字符串
    }

    /**
     * 设置http的相关设置，返回RequestConfig对象，将其作为参数设置给HttpGet对象
     * @return
     */
    public RequestConfig getConfig() {
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(1000) // 设置连接超时
                .setConnectionRequestTimeout(500) // 设置连接请求超时
                .setSocketTimeout(10000).build(); // 设置套接字超时
        return config;
    }
}
